package com.deer.wms.system.manage.service.impl;

import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.StringUtils;
import com.deer.wms.system.manage.dao.CodeRuleMapper;
import com.deer.wms.system.manage.model.coderule.CodeRule;
import com.deer.wms.system.manage.service.CodeRuleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author : wei
 * @since : 2021-10-27 17:28:25
 **/
@Service("codeRuleService")
@Transactional
public class CodeRuleServiceImpl extends SuperServiceImpl<CodeRuleMapper, CodeRule> implements CodeRuleService {

    static ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();

    @Override
    public String generateCode(String orderType, Map<String, String> params) {
        List<String> result = generateCode(orderType, params, 1);
        return result.size() >= 1 ? result.get(0) : "";
    }

    @Override
    public String generateCode(String orderType) {
        return generateCode(orderType, new HashMap<String, String>());
    }

    @Override
    public List<String> generateCode(String orderType, Map<String, String> params, int count) {
        Object lockObj = null;

        if (map.containsKey(orderType)) {
            lockObj = map.get(orderType);
        } else {
            lockObj = new Object();
            map.put(orderType, lockObj);
        }

        synchronized (lockObj) {
            return this.syncGenerate(orderType, params, count);
        }
    }

    @Override
    public void createCodeRule(CodeRule codeRule, CurrentUser currentUser) {
        codeRule.setCreateUserId(currentUser.getUserId());
        codeRule.setCreateTime(new Date());
        this.save(codeRule);
    }


    //    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public List<String> syncGenerate(String orderType, Map<String, String> params, int count) {
        CodeRule rule = this.getOneByField("code", orderType);

        if (null == rule) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "请在基础信息--系统设置--单据号管理中维护规则[" + orderType + "]");
        }
        // 单据号每日清零判断
        ruleTodayClear(rule, orderType);
//        Map<String, Object> map = new HashMap<>(1);
//        Map<String, Boolean> map2 = new HashMap<>(1);
//        map.put("code_rule_gid", rule.getId());
//        map2.put("seq", true);
//        List<CodeRuleDetail> items = this.codeRuleDetailService.getOrderListByMap(map, map2);

        // 没有维护规则，同时也没有维护脚本，直接通过默认规则生成
        return generateDefaultCode(rule, params, count);

    }

    /**
     * 判断单据号是否需要清零
     *
     * @param rule      规则
     * @param orderType 规则编码
     * @return List<String>
     */
    public CodeRule ruleTodayClear(CodeRule rule, String orderType) {
        // 单据号流水每日清零--修改人:张宇
        // 修改思路：code_rule增加一个最后使用时间字段,如果最后使用的时间与当前时间不是同一天,更新单据号规则的当前值为0,保存修改
        // this.updateById(rule); 再次获取规则流水号
        // 后序修改思路；单据号增加一个清零的标识状态 方便进行单据号管理
        Date nowDate = new Date();
        Date endUseDate = rule.getEndUseTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dateStr1 = sdf.format(nowDate);
        String dateStr2 = sdf.format(endUseDate);
        if (!dateStr1.equals(dateStr2)) {
            //最后使用的时间与当前时间不是同一天
            rule.setCurrentVal(0);
            rule.setEndUseTime(nowDate);
            this.updateById(rule);
            //重新获取单据号
            rule = this.getOneByField("code", orderType);
        }
        return rule;
    }

    /**
     * 未配置规则明细的情况下，生成编码.
     *
     * @param rule   规则编码
     * @param params 参数值集合
     * @param count  生成数量
     * @return List<String>
     */
    public List<String> generateDefaultCode(CodeRule rule, Map<String, String> params, int count) {
        List<String> result = new ArrayList<>();

        Integer currentVal = rule.getCurrentVal(); //当前值
        Integer stepVal = rule.getStepVal(); //步长
        Integer maxVal = rule.getMaxVal(); //最大值
        Integer minVal = rule.getMinVal(); //最小值
        Integer seqLen = maxVal.toString().length(); //流水码长度

        StringBuilder code = new StringBuilder(rule.getCode() + "-");

        /* 处理日期部分 */
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dateStr = sdf.format(date);
        code.append(dateStr).append("-");

        /* 处理流水号 */
        for (int i = 0; i < count; i++) {
            Integer seq = currentVal + stepVal;
            if (seq >= maxVal) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "单据[" + rule.getCode() + "]流水号超过最大值:" + maxVal);
            }
            //补齐流水码长度
            String seqStr = StringUtils.leftPad(seq.toString(), seqLen, "0");
            currentVal = seq;
            result.add(code + seqStr);
        }

        //保存当前步长
        rule.setCurrentVal(currentVal);
        //更新最后使用时间
        rule.setEndUseTime(date);
        this.updateById(rule);

        return result;
    }
}
